<?php

namespace App\Command\Make;

use Hyperf\Command\Annotation\Command;
use Hyperf\Utils\Str;
use Symfony\Component\Console\Input\InputOption;

#[Command]
class MakeServiceCommand extends GeneratorCommand
{
    public function __construct()
    {
        parent::__construct('make:service');
        $this->setDescription('Create a new service class');
    }

    protected function getStub(): string
    {
        return __DIR__ . '/stubs/service.model.stub';
    }

    protected function getDefaultNamespace(): string
    {
        return $this->rootNamespace() . 'Service';
    }

    protected function buildClass($name): string
    {
        $serviceNamespace = $this->getNamespace($name);

        $replace = [];

        if ($this->input->getOption('model')) {
            $replace = $this->buildModelReplacements($replace);
        }

        $replace["use {$serviceNamespace}\Service;\n"] = '';

        return str_replace(
            array_keys($replace), array_values($replace), parent::buildClass($name)
        );
    }

    protected function buildModelReplacements(array $replace): array
    {
        $modelClass = $this->parseModel($this->input->getOption('model'));
        return array_merge($replace, [
            'DummyFullModelClass' => $modelClass,
            '{{ namespacedModel }}' => $modelClass,
            '{{namespacedModel}}' => $modelClass,
            'DummyModelClass' => class_basename($modelClass),
            '{{ model }}' => class_basename($modelClass),
            '{{model}}' => class_basename($modelClass),
            'DummyModelVariable' => lcfirst(class_basename($modelClass)),
            '{{ modelVariable }}' => lcfirst(class_basename($modelClass)),
            '{{modelVariable}}' => lcfirst(class_basename($modelClass)),
        ]);
    }

    protected function parseModel(string $model): string
    {
        if (preg_match('([^A-Za-z0-9_/\\\\])', $model)) {
            throw new \Exception('Service name contains invalid characters.');
        }
        return $this->qualifyModel($model);
    }

    /**
     * Qualify the given service class base name.
     */
    protected function qualifyModel(string $model): string
    {
        $model = ltrim($model, '\\/');
        $model = str_replace('/', '\\', $model);
        $rootNamespace = $this->rootNamespace();
        if (Str::startsWith($model, $rootNamespace)) {
            return $model;
        }
        return is_dir(BASE_PATH . '/app/Model')
            ? $rootNamespace . 'Model\\' . $model
            : $rootNamespace . $model;
    }

    /**
     * Get the console command options.
     *
     * @return array
     */
    protected function getOptions(): array
    {
       return array_merge(parent::getOptions(), [
           ['model', 'm', InputOption::VALUE_OPTIONAL, 'Generate a service for the given model..'],
       ]);
    }

}